﻿#region Copyright ©2008-2010, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: then $
// Last Changed Date     $LastChangedDate: 2009-12-16 16:37:27 +0100 (Wed, 16 Dec 2009) $
// Last Changed Revision $Rev: 504 $
//
// ====================================================================================================
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace Tum.CollabXT.Wizard
{
    /// <summary>
    /// Management class for process- and tool providers.
    /// </summary>
    public class PluginManager
    {
        /// <summary>
        /// List of available process providers.
        /// </summary>
        private List<ProviderInfo> ProcessProviderList = new List<ProviderInfo>();

        /// <summary>
        /// List of available tool providers.
        /// </summary>
        private List<ProviderInfo> ToolProviderList = new List<ProviderInfo>();


        /// <summary>
        /// Constructor.
        /// </summary>
        public PluginManager()
        {
            try
            {
                string[] pluginFiles = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll");
                foreach (var curPluginFile in pluginFiles)
                {
                    try
                    {
                        Assembly pluginAssembly = Assembly.LoadFile(curPluginFile);

                        foreach (var curModule in pluginAssembly.GetModules())
                        {
                            Type[] t;
                            if ((t = GetInterfaceImplementingTypes(curModule, typeof(IProcessProvider))) != null)
                            {
                                foreach (Type curT in t)
                                {
                                    if (!ProviderInfo.AlreadyInList(ProcessProviderList, curPluginFile, curT))
                                        ProcessProviderList.Add(new ProcessProviderInfo(curPluginFile, curT));
                                }
                            }

                            if ((t = GetInterfaceImplementingTypes(curModule, typeof(IToolProvider))) != null)
                            {
                                foreach (Type curT in t)
                                {
                                    if (!ProviderInfo.AlreadyInList(ToolProviderList, curPluginFile, curT))
                                        ToolProviderList.Add(new ToolProviderInfo(curPluginFile, curT));
                                }
                            }
                        }
                    }
                    catch(Exception) { }
                }
            }
            catch (Exception e)
            {
                throw new CxtWizardException("Could not initalize plugin manager", e);
            }
        }

        /// <summary>
        /// Gets the list of types within a module that implement a certain interface.
        /// </summary>
        /// <param name="module">Module that contains the types to be found.</param>
        /// <param name="interfaceType">Interface that has to be implemented.</param>
        /// <returns>All types within the module that implement the interface.</returns>
        private static Type[] GetInterfaceImplementingTypes(Module module, Type interfaceType)
        {
            //Load types contained in the module
            Type[] moduleTypes;
            try
            {
                moduleTypes = module.GetTypes();
            }
            catch(ReflectionTypeLoadException e)
            {
                //Could not load all types. Get the correctly loaded ones
                moduleTypes = e.Types;
            }

            //Go through types
            List<Type> typeList = new List<Type>();
            foreach (var curModuleType in moduleTypes)
            {
                if (curModuleType != null)
                {
                    try
                    {
                        //Check, if our interface is contained
                        Type[] implementedTypes = curModuleType.FindInterfaces(InterfaceFilter, interfaceType);
                        if (implementedTypes.Length > 0)
                            typeList.Add(curModuleType);
                    }
                    catch(TargetInvocationException) { }
                }
            }
            return typeList.Count > 0 ? typeList.ToArray() : null;
        }

        /// <summary>
        /// Interface filter for use within GetInterfaceImplementingTypes
        /// </summary>
        static private bool InterfaceFilter(Type type, object typeToBeFound)
        {
            return type.FullName.Equals(((Type)typeToBeFound).FullName);
        }

        /// <summary>
        /// Gets all loaded tool providers.
        /// </summary>
        /// <returns>Loaded tool providers.</returns>
        public ToolProviderInfo[] GetToolProviders()
        {
            ToolProviderInfo[] infos = new ToolProviderInfo[ToolProviderList.Count];
            for (int a = 0; a < ToolProviderList.Count; a++)
                infos[a] = ToolProviderList[a] as ToolProviderInfo;
            return infos;
        }

        /// <summary>
        /// Gets all loaded process providers.
        /// </summary>
        /// <returns>Loaded process providers.</returns>
        public ProcessProviderInfo[] GetProcessProviders()
        {
            ProcessProviderInfo[] infos = new ProcessProviderInfo[ProcessProviderList.Count];
            for (int a = 0; a < ProcessProviderList.Count; a++)
                infos[a] = ProcessProviderList[a] as ProcessProviderInfo;
            return infos;
        }
    }
}